Statistics
| Branch: | Revision:

root / hw / slavio_intctl.c @ 3475187d

History | View | Annotate | Download (9 kB)

1 e80cfcfc bellard
/*
2 e80cfcfc bellard
 * QEMU Sparc SLAVIO interrupt controller emulation
3 e80cfcfc bellard
 * 
4 66321a11 bellard
 * Copyright (c) 2003-2005 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 66321a11 bellard
//#define DEBUG_IRQ
27 66321a11 bellard
28 66321a11 bellard
#ifdef DEBUG_IRQ
29 66321a11 bellard
#define DPRINTF(fmt, args...) \
30 66321a11 bellard
do { printf("IRQ: " fmt , ##args); } while (0)
31 66321a11 bellard
#else
32 66321a11 bellard
#define DPRINTF(fmt, args...)
33 66321a11 bellard
#endif
34 e80cfcfc bellard
35 e80cfcfc bellard
/*
36 e80cfcfc bellard
 * Registers of interrupt controller in sun4m.
37 e80cfcfc bellard
 *
38 e80cfcfc bellard
 * This is the interrupt controller part of chip STP2001 (Slave I/O), also
39 e80cfcfc bellard
 * produced as NCR89C105. See
40 e80cfcfc bellard
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
41 e80cfcfc bellard
 *
42 e80cfcfc bellard
 * There is a system master controller and one for each cpu.
43 e80cfcfc bellard
 * 
44 e80cfcfc bellard
 */
45 e80cfcfc bellard
46 e80cfcfc bellard
#define MAX_CPUS 16
47 e80cfcfc bellard
48 e80cfcfc bellard
typedef struct SLAVIO_INTCTLState {
49 e80cfcfc bellard
    uint32_t intreg_pending[MAX_CPUS];
50 e80cfcfc bellard
    uint32_t intregm_pending;
51 e80cfcfc bellard
    uint32_t intregm_disabled;
52 e80cfcfc bellard
    uint32_t target_cpu;
53 e80cfcfc bellard
#ifdef DEBUG_IRQ_COUNT
54 e80cfcfc bellard
    uint64_t irq_count[32];
55 e80cfcfc bellard
#endif
56 e80cfcfc bellard
} SLAVIO_INTCTLState;
57 e80cfcfc bellard
58 e80cfcfc bellard
#define INTCTL_MAXADDR 0xf
59 e80cfcfc bellard
#define INTCTLM_MAXADDR 0xf
60 66321a11 bellard
static void slavio_check_interrupts(void *opaque);
61 e80cfcfc bellard
62 e80cfcfc bellard
// per-cpu interrupt controller
63 e80cfcfc bellard
static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
64 e80cfcfc bellard
{
65 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
66 e80cfcfc bellard
    uint32_t saddr;
67 e80cfcfc bellard
    int cpu;
68 e80cfcfc bellard
69 e80cfcfc bellard
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
70 e80cfcfc bellard
    saddr = (addr & INTCTL_MAXADDR) >> 2;
71 e80cfcfc bellard
    switch (saddr) {
72 e80cfcfc bellard
    case 0:
73 e80cfcfc bellard
        return s->intreg_pending[cpu];
74 e80cfcfc bellard
    default:
75 e80cfcfc bellard
        break;
76 e80cfcfc bellard
    }
77 e80cfcfc bellard
    return 0;
78 e80cfcfc bellard
}
79 e80cfcfc bellard
80 e80cfcfc bellard
static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
81 e80cfcfc bellard
{
82 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
83 e80cfcfc bellard
    uint32_t saddr;
84 e80cfcfc bellard
    int cpu;
85 e80cfcfc bellard
86 e80cfcfc bellard
    cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
87 e80cfcfc bellard
    saddr = (addr & INTCTL_MAXADDR) >> 2;
88 e80cfcfc bellard
    switch (saddr) {
89 e80cfcfc bellard
    case 1: // clear pending softints
90 e80cfcfc bellard
        if (val & 0x4000)
91 e80cfcfc bellard
            val |= 80000000;
92 e80cfcfc bellard
        val &= 0xfffe0000;
93 e80cfcfc bellard
        s->intreg_pending[cpu] &= ~val;
94 66321a11 bellard
        DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
95 e80cfcfc bellard
        break;
96 e80cfcfc bellard
    case 2: // set softint
97 e80cfcfc bellard
        val &= 0xfffe0000;
98 e80cfcfc bellard
        s->intreg_pending[cpu] |= val;
99 66321a11 bellard
        DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
100 e80cfcfc bellard
        break;
101 e80cfcfc bellard
    default:
102 e80cfcfc bellard
        break;
103 e80cfcfc bellard
    }
104 e80cfcfc bellard
}
105 e80cfcfc bellard
106 e80cfcfc bellard
static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
107 e80cfcfc bellard
    slavio_intctl_mem_readl,
108 e80cfcfc bellard
    slavio_intctl_mem_readl,
109 e80cfcfc bellard
    slavio_intctl_mem_readl,
110 e80cfcfc bellard
};
111 e80cfcfc bellard
112 e80cfcfc bellard
static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
113 e80cfcfc bellard
    slavio_intctl_mem_writel,
114 e80cfcfc bellard
    slavio_intctl_mem_writel,
115 e80cfcfc bellard
    slavio_intctl_mem_writel,
116 e80cfcfc bellard
};
117 e80cfcfc bellard
118 e80cfcfc bellard
// master system interrupt controller
119 e80cfcfc bellard
static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
120 e80cfcfc bellard
{
121 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
122 e80cfcfc bellard
    uint32_t saddr;
123 e80cfcfc bellard
124 e80cfcfc bellard
    saddr = (addr & INTCTLM_MAXADDR) >> 2;
125 e80cfcfc bellard
    switch (saddr) {
126 e80cfcfc bellard
    case 0:
127 6bae7071 bellard
        return s->intregm_pending & 0x7fffffff;
128 e80cfcfc bellard
    case 1:
129 e80cfcfc bellard
        return s->intregm_disabled;
130 e80cfcfc bellard
    case 4:
131 e80cfcfc bellard
        return s->target_cpu;
132 e80cfcfc bellard
    default:
133 e80cfcfc bellard
        break;
134 e80cfcfc bellard
    }
135 e80cfcfc bellard
    return 0;
136 e80cfcfc bellard
}
137 e80cfcfc bellard
138 e80cfcfc bellard
static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
139 e80cfcfc bellard
{
140 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
141 e80cfcfc bellard
    uint32_t saddr;
142 e80cfcfc bellard
143 e80cfcfc bellard
    saddr = (addr & INTCTLM_MAXADDR) >> 2;
144 e80cfcfc bellard
    switch (saddr) {
145 e80cfcfc bellard
    case 2: // clear (enable)
146 6bae7071 bellard
        // Force clear unused bits
147 3475187d bellard
        val &= ~0x4fb2007f;
148 e80cfcfc bellard
        s->intregm_disabled &= ~val;
149 66321a11 bellard
        DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
150 66321a11 bellard
        slavio_check_interrupts(s);
151 e80cfcfc bellard
        break;
152 e80cfcfc bellard
    case 3: // set (disable, clear pending)
153 6bae7071 bellard
        // Force clear unused bits
154 3475187d bellard
        val &= ~0x4fb2007f;
155 e80cfcfc bellard
        s->intregm_disabled |= val;
156 e80cfcfc bellard
        s->intregm_pending &= ~val;
157 66321a11 bellard
        DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
158 e80cfcfc bellard
        break;
159 e80cfcfc bellard
    case 4:
160 e80cfcfc bellard
        s->target_cpu = val & (MAX_CPUS - 1);
161 66321a11 bellard
        DPRINTF("Set master irq cpu %d\n", s->target_cpu);
162 e80cfcfc bellard
        break;
163 e80cfcfc bellard
    default:
164 e80cfcfc bellard
        break;
165 e80cfcfc bellard
    }
166 e80cfcfc bellard
}
167 e80cfcfc bellard
168 e80cfcfc bellard
static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
169 e80cfcfc bellard
    slavio_intctlm_mem_readl,
170 e80cfcfc bellard
    slavio_intctlm_mem_readl,
171 e80cfcfc bellard
    slavio_intctlm_mem_readl,
172 e80cfcfc bellard
};
173 e80cfcfc bellard
174 e80cfcfc bellard
static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
175 e80cfcfc bellard
    slavio_intctlm_mem_writel,
176 e80cfcfc bellard
    slavio_intctlm_mem_writel,
177 e80cfcfc bellard
    slavio_intctlm_mem_writel,
178 e80cfcfc bellard
};
179 e80cfcfc bellard
180 e80cfcfc bellard
void slavio_pic_info(void *opaque)
181 e80cfcfc bellard
{
182 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
183 e80cfcfc bellard
    int i;
184 e80cfcfc bellard
185 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
186 e80cfcfc bellard
        term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
187 e80cfcfc bellard
    }
188 e80cfcfc bellard
    term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
189 e80cfcfc bellard
}
190 e80cfcfc bellard
191 e80cfcfc bellard
void slavio_irq_info(void *opaque)
192 e80cfcfc bellard
{
193 e80cfcfc bellard
#ifndef DEBUG_IRQ_COUNT
194 e80cfcfc bellard
    term_printf("irq statistic code not compiled.\n");
195 e80cfcfc bellard
#else
196 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
197 e80cfcfc bellard
    int i;
198 e80cfcfc bellard
    int64_t count;
199 e80cfcfc bellard
200 e80cfcfc bellard
    term_printf("IRQ statistics:\n");
201 e80cfcfc bellard
    for (i = 0; i < 32; i++) {
202 e80cfcfc bellard
        count = s->irq_count[i];
203 e80cfcfc bellard
        if (count > 0)
204 e80cfcfc bellard
            term_printf("%2d: %lld\n", i, count);
205 e80cfcfc bellard
    }
206 e80cfcfc bellard
#endif
207 e80cfcfc bellard
}
208 e80cfcfc bellard
209 e80cfcfc bellard
static const uint32_t intbit_to_level[32] = {
210 e80cfcfc bellard
    2, 3, 5, 7, 9, 11, 0, 14,        3, 5, 7, 9, 11, 13, 12, 12,
211 3475187d bellard
    6, 0, 4, 10, 8, 0, 11, 0,        0, 0, 0, 0, 15, 0, 15, 0,
212 e80cfcfc bellard
};
213 e80cfcfc bellard
214 66321a11 bellard
static void slavio_check_interrupts(void *opaque)
215 66321a11 bellard
{
216 66321a11 bellard
    SLAVIO_INTCTLState *s = opaque;
217 66321a11 bellard
    uint32_t pending = s->intregm_pending;
218 66321a11 bellard
    unsigned int i, max = 0;
219 66321a11 bellard
220 66321a11 bellard
    pending &= ~s->intregm_disabled;
221 66321a11 bellard
222 66321a11 bellard
    if (pending && !(s->intregm_disabled & 0x80000000)) {
223 66321a11 bellard
        for (i = 0; i < 32; i++) {
224 66321a11 bellard
            if (pending & (1 << i)) {
225 66321a11 bellard
                if (max < intbit_to_level[i])
226 66321a11 bellard
                    max = intbit_to_level[i];
227 66321a11 bellard
            }
228 66321a11 bellard
        }
229 66321a11 bellard
        if (cpu_single_env->interrupt_index == 0) {
230 66321a11 bellard
            DPRINTF("Triggered pil %d\n", max);
231 66321a11 bellard
#ifdef DEBUG_IRQ_COUNT
232 66321a11 bellard
            s->irq_count[max]++;
233 66321a11 bellard
#endif
234 66321a11 bellard
            cpu_single_env->interrupt_index = TT_EXTINT | max;
235 66321a11 bellard
            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
236 66321a11 bellard
        }
237 66321a11 bellard
        else
238 66321a11 bellard
            DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, cpu_single_env->interrupt_index);
239 66321a11 bellard
    }
240 66321a11 bellard
    else
241 66321a11 bellard
        DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
242 66321a11 bellard
}
243 66321a11 bellard
244 e80cfcfc bellard
/*
245 e80cfcfc bellard
 * "irq" here is the bit number in the system interrupt register to
246 e80cfcfc bellard
 * separate serial and keyboard interrupts sharing a level.
247 e80cfcfc bellard
 */
248 e80cfcfc bellard
void slavio_pic_set_irq(void *opaque, int irq, int level)
249 e80cfcfc bellard
{
250 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
251 e80cfcfc bellard
252 66321a11 bellard
    DPRINTF("Set irq %d level %d\n", irq, level);
253 e80cfcfc bellard
    if (irq < 32) {
254 e80cfcfc bellard
        uint32_t mask = 1 << irq;
255 e80cfcfc bellard
        uint32_t pil = intbit_to_level[irq];
256 e80cfcfc bellard
        if (pil > 0) {
257 e80cfcfc bellard
            if (level) {
258 e80cfcfc bellard
                s->intregm_pending |= mask;
259 e80cfcfc bellard
                s->intreg_pending[s->target_cpu] |= 1 << pil;
260 e80cfcfc bellard
            }
261 e80cfcfc bellard
            else {
262 e80cfcfc bellard
                s->intregm_pending &= ~mask;
263 e80cfcfc bellard
                s->intreg_pending[s->target_cpu] &= ~(1 << pil);
264 e80cfcfc bellard
            }
265 e80cfcfc bellard
        }
266 e80cfcfc bellard
    }
267 66321a11 bellard
    slavio_check_interrupts(s);
268 e80cfcfc bellard
}
269 e80cfcfc bellard
270 e80cfcfc bellard
static void slavio_intctl_save(QEMUFile *f, void *opaque)
271 e80cfcfc bellard
{
272 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
273 e80cfcfc bellard
    int i;
274 e80cfcfc bellard
    
275 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
276 e80cfcfc bellard
        qemu_put_be32s(f, &s->intreg_pending[i]);
277 e80cfcfc bellard
    }
278 e80cfcfc bellard
    qemu_put_be32s(f, &s->intregm_pending);
279 e80cfcfc bellard
    qemu_put_be32s(f, &s->intregm_disabled);
280 e80cfcfc bellard
    qemu_put_be32s(f, &s->target_cpu);
281 e80cfcfc bellard
}
282 e80cfcfc bellard
283 e80cfcfc bellard
static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
284 e80cfcfc bellard
{
285 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
286 e80cfcfc bellard
    int i;
287 e80cfcfc bellard
288 e80cfcfc bellard
    if (version_id != 1)
289 e80cfcfc bellard
        return -EINVAL;
290 e80cfcfc bellard
291 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
292 e80cfcfc bellard
        qemu_get_be32s(f, &s->intreg_pending[i]);
293 e80cfcfc bellard
    }
294 e80cfcfc bellard
    qemu_get_be32s(f, &s->intregm_pending);
295 e80cfcfc bellard
    qemu_get_be32s(f, &s->intregm_disabled);
296 e80cfcfc bellard
    qemu_get_be32s(f, &s->target_cpu);
297 e80cfcfc bellard
    return 0;
298 e80cfcfc bellard
}
299 e80cfcfc bellard
300 e80cfcfc bellard
static void slavio_intctl_reset(void *opaque)
301 e80cfcfc bellard
{
302 e80cfcfc bellard
    SLAVIO_INTCTLState *s = opaque;
303 e80cfcfc bellard
    int i;
304 e80cfcfc bellard
305 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
306 e80cfcfc bellard
        s->intreg_pending[i] = 0;
307 e80cfcfc bellard
    }
308 6bae7071 bellard
    s->intregm_disabled = ~0xffb2007f;
309 e80cfcfc bellard
    s->intregm_pending = 0;
310 e80cfcfc bellard
    s->target_cpu = 0;
311 e80cfcfc bellard
}
312 e80cfcfc bellard
313 e80cfcfc bellard
void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
314 e80cfcfc bellard
{
315 e80cfcfc bellard
    int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
316 e80cfcfc bellard
    SLAVIO_INTCTLState *s;
317 e80cfcfc bellard
318 e80cfcfc bellard
    s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
319 e80cfcfc bellard
    if (!s)
320 e80cfcfc bellard
        return NULL;
321 e80cfcfc bellard
322 e80cfcfc bellard
    for (i = 0; i < MAX_CPUS; i++) {
323 e80cfcfc bellard
        slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
324 e80cfcfc bellard
        cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
325 e80cfcfc bellard
    }
326 e80cfcfc bellard
327 e80cfcfc bellard
    slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
328 e80cfcfc bellard
    cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
329 e80cfcfc bellard
330 e80cfcfc bellard
    register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
331 e80cfcfc bellard
    qemu_register_reset(slavio_intctl_reset, s);
332 e80cfcfc bellard
    slavio_intctl_reset(s);
333 e80cfcfc bellard
    return s;
334 e80cfcfc bellard
}