Statistics
| Branch: | Revision:

root / hw / slavio_intctl.c @ afc7df11

History | View | Annotate | Download (7.8 kB)

1 e80cfcfc bellard
/*
2 e80cfcfc bellard
 * QEMU Sparc SLAVIO interrupt controller emulation
3 e80cfcfc bellard
 * 
4 e80cfcfc bellard
 * Copyright (c) 2003-2004 Fabrice Bellard
5 e80cfcfc bellard
 * 
6 e80cfcfc bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 e80cfcfc bellard
 * of this software and associated documentation files (the "Software"), to deal
8 e80cfcfc bellard
 * in the Software without restriction, including without limitation the rights
9 e80cfcfc bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 e80cfcfc bellard
 * copies of the Software, and to permit persons to whom the Software is
11 e80cfcfc bellard
 * furnished to do so, subject to the following conditions:
12 e80cfcfc bellard
 *
13 e80cfcfc bellard
 * The above copyright notice and this permission notice shall be included in
14 e80cfcfc bellard
 * all copies or substantial portions of the Software.
15 e80cfcfc bellard
 *
16 e80cfcfc bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 e80cfcfc bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 e80cfcfc bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 e80cfcfc bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 e80cfcfc bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 e80cfcfc bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 e80cfcfc bellard
 * THE SOFTWARE.
23 e80cfcfc bellard
 */
24 e80cfcfc bellard
#include "vl.h"
25 e80cfcfc bellard
//#define DEBUG_IRQ_COUNT
26 e80cfcfc bellard
27 e80cfcfc bellard
/*
28 e80cfcfc bellard
 * Registers of interrupt controller in sun4m.
29 e80cfcfc bellard
 *
30 e80cfcfc bellard
 * This is the interrupt controller part of chip STP2001 (Slave I/O), also
31 e80cfcfc bellard
 * produced as NCR89C105. See
32 e80cfcfc bellard
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
33 e80cfcfc bellard
 *
34 e80cfcfc bellard
 * There is a system master controller and one for each cpu.
35 e80cfcfc bellard
 * 
36 e80cfcfc bellard
 */
37 e80cfcfc bellard
38 e80cfcfc bellard
#define MAX_CPUS 16
39 e80cfcfc bellard
40 e80cfcfc bellard
typedef struct SLAVIO_INTCTLState {
41 e80cfcfc bellard
    uint32_t intreg_pending[MAX_CPUS];
42 e80cfcfc bellard
    uint32_t intregm_pending;
43 e80cfcfc bellard
    uint32_t intregm_disabled;
44 e80cfcfc bellard
    uint32_t target_cpu;
45 e80cfcfc bellard
#ifdef DEBUG_IRQ_COUNT
46 e80cfcfc bellard
    uint64_t irq_count[32];
47 e80cfcfc bellard
#endif
48 e80cfcfc bellard
} SLAVIO_INTCTLState;
49 e80cfcfc bellard
50 e80cfcfc bellard
#define INTCTL_MAXADDR 0xf
51 e80cfcfc bellard
#define INTCTLM_MAXADDR 0xf
52 e80cfcfc bellard
53 e80cfcfc bellard
// per-cpu interrupt controller
54 e80cfcfc bellard
static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
55 e80cfcfc bellard
{
56 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
57 e80cfcfc bellard
    uint32_t saddr;
58 e80cfcfc bellard
    int cpu;
59 e80cfcfc bellard
60 e80cfcfc bellard
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
61 e80cfcfc bellard
    saddr = (addr & INTCTL_MAXADDR) >> 2;
62 e80cfcfc bellard
    switch (saddr) {
63 e80cfcfc bellard
    case 0:
64 e80cfcfc bellard
        return s->intreg_pending[cpu];
65 e80cfcfc bellard
    default:
66 e80cfcfc bellard
        break;
67 e80cfcfc bellard
    }
68 e80cfcfc bellard
    return 0;
69 e80cfcfc bellard
}
70 e80cfcfc bellard
71 e80cfcfc bellard
static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
72 e80cfcfc bellard
{
73 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
74 e80cfcfc bellard
    uint32_t saddr;
75 e80cfcfc bellard
    int cpu;
76 e80cfcfc bellard
77 e80cfcfc bellard
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
78 e80cfcfc bellard
    saddr = (addr & INTCTL_MAXADDR) >> 2;
79 e80cfcfc bellard
    switch (saddr) {
80 e80cfcfc bellard
    case 1: // clear pending softints
81 e80cfcfc bellard
        if (val & 0x4000)
82 e80cfcfc bellard
            val |= 80000000;
83 e80cfcfc bellard
        val &= 0xfffe0000;
84 e80cfcfc bellard
        s->intreg_pending[cpu] &= ~val;
85 e80cfcfc bellard
        break;
86 e80cfcfc bellard
    case 2: // set softint
87 e80cfcfc bellard
        val &= 0xfffe0000;
88 e80cfcfc bellard
        s->intreg_pending[cpu] |= val;
89 e80cfcfc bellard
        break;
90 e80cfcfc bellard
    default:
91 e80cfcfc bellard
        break;
92 e80cfcfc bellard
    }
93 e80cfcfc bellard
}
94 e80cfcfc bellard
95 e80cfcfc bellard
static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
96 e80cfcfc bellard
    slavio_intctl_mem_readl,
97 e80cfcfc bellard
    slavio_intctl_mem_readl,
98 e80cfcfc bellard
    slavio_intctl_mem_readl,
99 e80cfcfc bellard
};
100 e80cfcfc bellard
101 e80cfcfc bellard
static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
102 e80cfcfc bellard
    slavio_intctl_mem_writel,
103 e80cfcfc bellard
    slavio_intctl_mem_writel,
104 e80cfcfc bellard
    slavio_intctl_mem_writel,
105 e80cfcfc bellard
};
106 e80cfcfc bellard
107 e80cfcfc bellard
// master system interrupt controller
108 e80cfcfc bellard
static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
109 e80cfcfc bellard
{
110 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
111 e80cfcfc bellard
    uint32_t saddr;
112 e80cfcfc bellard
113 e80cfcfc bellard
    saddr = (addr & INTCTLM_MAXADDR) >> 2;
114 e80cfcfc bellard
    switch (saddr) {
115 e80cfcfc bellard
    case 0:
116 6bae7071 bellard
        return s->intregm_pending & 0x7fffffff;
117 e80cfcfc bellard
    case 1:
118 e80cfcfc bellard
        return s->intregm_disabled;
119 e80cfcfc bellard
    case 4:
120 e80cfcfc bellard
        return s->target_cpu;
121 e80cfcfc bellard
    default:
122 e80cfcfc bellard
        break;
123 e80cfcfc bellard
    }
124 e80cfcfc bellard
    return 0;
125 e80cfcfc bellard
}
126 e80cfcfc bellard
127 e80cfcfc bellard
static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
128 e80cfcfc bellard
{
129 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
130 e80cfcfc bellard
    uint32_t saddr;
131 e80cfcfc bellard
132 e80cfcfc bellard
    saddr = (addr & INTCTLM_MAXADDR) >> 2;
133 e80cfcfc bellard
    switch (saddr) {
134 e80cfcfc bellard
    case 2: // clear (enable)
135 6bae7071 bellard
        // Force clear unused bits
136 6bae7071 bellard
        val &= ~0x7fb2007f;
137 e80cfcfc bellard
        s->intregm_disabled &= ~val;
138 e80cfcfc bellard
        break;
139 e80cfcfc bellard
    case 3: // set (disable, clear pending)
140 6bae7071 bellard
        // Force clear unused bits
141 e80cfcfc bellard
        val &= ~0x7fb2007f;
142 e80cfcfc bellard
        s->intregm_disabled |= val;
143 e80cfcfc bellard
        s->intregm_pending &= ~val;
144 e80cfcfc bellard
        break;
145 e80cfcfc bellard
    case 4:
146 e80cfcfc bellard
        s->target_cpu = val & (MAX_CPUS - 1);
147 e80cfcfc bellard
        break;
148 e80cfcfc bellard
    default:
149 e80cfcfc bellard
        break;
150 e80cfcfc bellard
    }
151 e80cfcfc bellard
}
152 e80cfcfc bellard
153 e80cfcfc bellard
static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
154 e80cfcfc bellard
    slavio_intctlm_mem_readl,
155 e80cfcfc bellard
    slavio_intctlm_mem_readl,
156 e80cfcfc bellard
    slavio_intctlm_mem_readl,
157 e80cfcfc bellard
};
158 e80cfcfc bellard
159 e80cfcfc bellard
static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
160 e80cfcfc bellard
    slavio_intctlm_mem_writel,
161 e80cfcfc bellard
    slavio_intctlm_mem_writel,
162 e80cfcfc bellard
    slavio_intctlm_mem_writel,
163 e80cfcfc bellard
};
164 e80cfcfc bellard
165 e80cfcfc bellard
void slavio_pic_info(void *opaque)
166 e80cfcfc bellard
{
167 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
168 e80cfcfc bellard
    int i;
169 e80cfcfc bellard
170 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
171 e80cfcfc bellard
        term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
172 e80cfcfc bellard
    }
173 e80cfcfc bellard
    term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
174 e80cfcfc bellard
}
175 e80cfcfc bellard
176 e80cfcfc bellard
void slavio_irq_info(void *opaque)
177 e80cfcfc bellard
{
178 e80cfcfc bellard
#ifndef DEBUG_IRQ_COUNT
179 e80cfcfc bellard
    term_printf("irq statistic code not compiled.\n");
180 e80cfcfc bellard
#else
181 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
182 e80cfcfc bellard
    int i;
183 e80cfcfc bellard
    int64_t count;
184 e80cfcfc bellard
185 e80cfcfc bellard
    term_printf("IRQ statistics:\n");
186 e80cfcfc bellard
    for (i = 0; i < 32; i++) {
187 e80cfcfc bellard
        count = s->irq_count[i];
188 e80cfcfc bellard
        if (count > 0)
189 e80cfcfc bellard
            term_printf("%2d: %lld\n", i, count);
190 e80cfcfc bellard
    }
191 e80cfcfc bellard
#endif
192 e80cfcfc bellard
}
193 e80cfcfc bellard
194 e80cfcfc bellard
static const uint32_t intbit_to_level[32] = {
195 e80cfcfc bellard
    2, 3, 5, 7, 9, 11, 0, 14,        3, 5, 7, 9, 11, 13, 12, 12,
196 e80cfcfc bellard
    6, 0, 4, 10, 8, 0, 11, 0,        0, 0, 0, 0, 15, 0, 0, 0,
197 e80cfcfc bellard
};
198 e80cfcfc bellard
199 e80cfcfc bellard
/*
200 e80cfcfc bellard
 * "irq" here is the bit number in the system interrupt register to
201 e80cfcfc bellard
 * separate serial and keyboard interrupts sharing a level.
202 e80cfcfc bellard
 */
203 e80cfcfc bellard
void slavio_pic_set_irq(void *opaque, int irq, int level)
204 e80cfcfc bellard
{
205 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
206 e80cfcfc bellard
207 e80cfcfc bellard
    if (irq < 32) {
208 e80cfcfc bellard
        uint32_t mask = 1 << irq;
209 e80cfcfc bellard
        uint32_t pil = intbit_to_level[irq];
210 e80cfcfc bellard
        if (pil > 0) {
211 e80cfcfc bellard
            if (level) {
212 e80cfcfc bellard
                s->intregm_pending |= mask;
213 e80cfcfc bellard
                s->intreg_pending[s->target_cpu] |= 1 << pil;
214 e80cfcfc bellard
            }
215 e80cfcfc bellard
            else {
216 e80cfcfc bellard
                s->intregm_pending &= ~mask;
217 e80cfcfc bellard
                s->intreg_pending[s->target_cpu] &= ~(1 << pil);
218 e80cfcfc bellard
            }
219 e80cfcfc bellard
            if (level &&
220 e80cfcfc bellard
                !(s->intregm_disabled & mask) &&
221 e80cfcfc bellard
                !(s->intregm_disabled & 0x80000000) &&
222 e80cfcfc bellard
                (pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) {
223 e80cfcfc bellard
#ifdef DEBUG_IRQ_COUNT
224 e80cfcfc bellard
                if (level == 1)
225 e80cfcfc bellard
                    s->irq_count[pil]++;
226 e80cfcfc bellard
#endif
227 e80cfcfc bellard
                cpu_single_env->interrupt_index = TT_EXTINT | pil;
228 e80cfcfc bellard
                cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
229 e80cfcfc bellard
            }
230 e80cfcfc bellard
        }
231 e80cfcfc bellard
    }
232 e80cfcfc bellard
}
233 e80cfcfc bellard
234 e80cfcfc bellard
static void slavio_intctl_save(QEMUFile *f, void *opaque)
235 e80cfcfc bellard
{
236 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
237 e80cfcfc bellard
    int i;
238 e80cfcfc bellard
    
239 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
240 e80cfcfc bellard
        qemu_put_be32s(f, &s->intreg_pending[i]);
241 e80cfcfc bellard
    }
242 e80cfcfc bellard
    qemu_put_be32s(f, &s->intregm_pending);
243 e80cfcfc bellard
    qemu_put_be32s(f, &s->intregm_disabled);
244 e80cfcfc bellard
    qemu_put_be32s(f, &s->target_cpu);
245 e80cfcfc bellard
}
246 e80cfcfc bellard
247 e80cfcfc bellard
static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
248 e80cfcfc bellard
{
249 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
250 e80cfcfc bellard
    int i;
251 e80cfcfc bellard
252 e80cfcfc bellard
    if (version_id != 1)
253 e80cfcfc bellard
        return -EINVAL;
254 e80cfcfc bellard
255 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
256 e80cfcfc bellard
        qemu_get_be32s(f, &s->intreg_pending[i]);
257 e80cfcfc bellard
    }
258 e80cfcfc bellard
    qemu_get_be32s(f, &s->intregm_pending);
259 e80cfcfc bellard
    qemu_get_be32s(f, &s->intregm_disabled);
260 e80cfcfc bellard
    qemu_get_be32s(f, &s->target_cpu);
261 e80cfcfc bellard
    return 0;
262 e80cfcfc bellard
}
263 e80cfcfc bellard
264 e80cfcfc bellard
static void slavio_intctl_reset(void *opaque)
265 e80cfcfc bellard
{
266 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
267 e80cfcfc bellard
    int i;
268 e80cfcfc bellard
269 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
270 e80cfcfc bellard
        s->intreg_pending[i] = 0;
271 e80cfcfc bellard
    }
272 6bae7071 bellard
    s->intregm_disabled = ~0xffb2007f;
273 e80cfcfc bellard
    s->intregm_pending = 0;
274 e80cfcfc bellard
    s->target_cpu = 0;
275 e80cfcfc bellard
}
276 e80cfcfc bellard
277 e80cfcfc bellard
void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
278 e80cfcfc bellard
{
279 e80cfcfc bellard
    int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
280 e80cfcfc bellard
    SLAVIO_INTCTLState *s;
281 e80cfcfc bellard
282 e80cfcfc bellard
    s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
283 e80cfcfc bellard
    if (!s)
284 e80cfcfc bellard
        return NULL;
285 e80cfcfc bellard
286 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
287 e80cfcfc bellard
        slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
288 e80cfcfc bellard
        cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
289 e80cfcfc bellard
    }
290 e80cfcfc bellard
291 e80cfcfc bellard
    slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
292 e80cfcfc bellard
    cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
293 e80cfcfc bellard
294 e80cfcfc bellard
    register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
295 e80cfcfc bellard
    qemu_register_reset(slavio_intctl_reset, s);
296 e80cfcfc bellard
    slavio_intctl_reset(s);
297 e80cfcfc bellard
    return s;
298 e80cfcfc bellard
}